<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Canvas签名</title>

  <style>
    #app {
      border: 2px blue dashed;
    }
  </style>
</head>

<body>
  <canvas id="app" width="500" height="300"></canvas>
  <button onclick="clearCanvas()">清除</button>
  <button onclick="downCanvas()">导出</button>

  <script>
    const cvs = document.getElementById('app');

    const ctx = getCanvasContext2D()
    ctx.strokeStyle = 'rgba(255,0,0,0.5)'
    ctx.lineWidth = 5

    let drawing = false

    // document.oncontextmenu = e => false

    cvs.addEventListener('contextmenu', e => {
      e.preventDefault()
    })
    cvs.addEventListener('mousedown', e => {
      drawing = true
      ctx.beginPath()
      ctx.moveTo(e.clientX - cvs.offsetLeft, e.clientY - cvs.offsetTop)
    })

    cvs.addEventListener('mousemove', e => {
      if (!drawing) return
      ctx.lineTo(e.clientX - cvs.offsetLeft, e.clientY - cvs.offsetTop)
      //ctx.closePath() // 不闭合路径则毛刺很多
      ctx.stroke()

      // 不开启新路径则每次stroke会再次绘制之前的线，如果有透明度的则显示的与预期不一致
      ctx.beginPath()
      ctx.moveTo(e.clientX - cvs.offsetLeft, e.clientY - cvs.offsetTop)
    })

    cvs.addEventListener('mouseup', e => {
      drawing = false
    })

    /**
     * 获取canvas上下文对象2D版本，此处加入jsdoc以便可以获得vscode的代码提示
     * @return {CanvasRenderingContext2D}
     */
    function getCanvasContext2D() {
      return cvs.getContext('2d')
    }

    //////////////////////
    function clearCanvas() {
      ctx.clearRect(0, 0, cvs.width, cvs.height)
    }

    function downCanvas() {
      const dataURL = cvs.toDataURL('image/png');
      // 创建一个 <a> 元素
      const link = document.createElement('a');
      // 将 DataURL 赋值给 <a> 元素的 href 属性
      link.href = dataURL;
      // 设置下载的文件名
      link.download = 'signature.png';
      // 触发 <a> 元素的点击事件，以便下载图片
      link.click();
    }
  </script>
</body>

</html>